﻿using System;
using log4net;
using System.Collections.Generic;
using RakutenCrawler.Repository;
using System.Linq;


namespace RakutenCrawler
{
    class Program
    {
        static ILog log = LogManager.GetLogger("Rakuten");
        const int MaxNumberProductsPerCategory = 250;

        static void Main(string[] args)
        {
            //var validSubGenres = GetValidSubGenre();
            //DisableGenres();

            //foreach (var subGenre in validSubGenres)
            //{
            //    var pCategories = FilterCategoryLinkForSubGenre(subGenre);
            //    foreach (var pCategory in pCategories)
            //    {
            //        FilterProductCategoryToCrawl(pCategory.ProductCategoryId);
            //    }
            //}

            RunBot();


            Console.WriteLine("I'm done. Press to exit");
            Console.ReadKey();
        }

        private static void RunBot()
        {
            var bot = new RakutenBot();
            bot.Login("dhlong@gmail.com", "3Pxilon3");
            bot.Logout();
        }

        private static void RunCrawler()
        {
            Console.WriteLine("Option: ");
            Console.WriteLine("-  Press 'n': Execute new scheduler");
            Console.WriteLine("-  Press 'o': Execute scheduled process");
            Console.WriteLine("-  Press any other key to exit");

            var key = Console.ReadKey();
            var engine = new CrawlerEngine();
            switch (key.Key)
            {
                case ConsoleKey.N:
                    engine.ExecuteNewScheduler();
                    break;
                case ConsoleKey.O:
                    engine.ExecuteScheduledProcess();
                    break;
                default:
                    Console.WriteLine("I quit");
                    break;
            }
        }            

        private static List<SubGenre> GetValidSubGenre()
        {
            var subgenres = new List<SubGenre>();
            using (var subGenreRepo = new SubGenreRepository(true))
            {
                foreach (var subgenre in subGenreRepo.All)
                {
                    if (subgenre.SubGenreURL.Contains("http://www.rakuten.co.jp/category") && subgenre.ProductCategories.Count > 0)
                        subgenres.Add(subgenre);
                    else
                    {
                        subgenre.IsDelete = true;
                        subGenreRepo.InsertOrUpdate(subgenre);

                        DisableLinkForSubGenre(subgenre.SubGenreId);
                    }
                }

                subGenreRepo.Save();
            }

            return subgenres;
        }

        private static void DisableLinkForSubGenre(int subGenreId)
        {
            var linkRepo = new LinkRepository();
            foreach (var link in linkRepo.FindBy(l => l.SubGenreId == subGenreId))
            {
                link.IsDelete = true;
                linkRepo.InsertOrUpdate(link);
            }

            linkRepo.Save();
            linkRepo.Dispose();
        }


        private static void DisableGenres()
        {
            var genreRepo = new GenreRepository(true, true);
            foreach (var genre in genreRepo.All)
            {
                var availbaleSubGenres = genre.SubGenres.Where(s => !s.IsDelete).ToArray();
                if (availbaleSubGenres.Length == 0)
                {
                    genre.IsDelete = true;
                    genreRepo.InsertOrUpdate(genre);
                }
            }

            genreRepo.Save();
            genreRepo.Dispose();
        }

        private static void DisableProductCategory(int pCategoryId)
        {
            var pCategoryRepo = new ProductCategoryRepository();
            var linkRepo = new LinkRepository();
            var pCategory = pCategoryRepo.Single(p => p.ProductCategoryId == pCategoryId);
            pCategory.IsDelete = true;
            pCategoryRepo.InsertOrUpdate(pCategory);

            foreach (var link in linkRepo.FindBy(l => l.ProductCategoryId == pCategoryId))
            {
                link.IsDelete = true;
                linkRepo.InsertOrUpdate(link);
            }

            pCategoryRepo.Save();
            pCategoryRepo.Dispose();

            linkRepo.Save();
            linkRepo.Dispose();
        }

           

        private static void FilterProductCategoryToCrawl(int pCategoryId)
        {
            var pRepo = new ProductCategoryRepository(true);
            var linkRepo = new LinkRepository();
            var pCategory = pRepo.Single(p => p.ProductCategoryId == pCategoryId);

            if (pCategory.Products.Count >= MaxNumberProductsPerCategory)
            {
                foreach (var link in linkRepo.FindBy(l => l.ProductCategoryId == pCategoryId))
                {
                    link.IsDelete = true;
                    linkRepo.InsertOrUpdate(link);
                }
            }

            linkRepo.Save();
            linkRepo.Dispose();
        }

        
        private static List<ProductCategory> FilterCategoryLinkForSubGenre(SubGenre subgenre)
        {
            var pCategoryRepo = new ProductCategoryRepository(true);
            var pCategories = new List<ProductCategory>();

            const int minNumberOfCategory = 3;
            const int maxNumberOfCategory = 7;
            const int minNumberOfSubCategory = 2;
            const int maxNumberOfSubCategory = 6;

            var random = new Random((int)DateTime.Now.Ticks);
            var numberOfCategory = random.Next(minNumberOfCategory, maxNumberOfCategory);
            
            var categories = pCategoryRepo.FindBy(c => c.SubGenreId == subgenre.SubGenreId).ToList();

            var categoriesCannotDelete = categories.Where(c => c.Products.Count > 0);

            var cannotDeleteParents = categoriesCannotDelete.Where(c => c.ParentProductCategoryId == null).Take(numberOfCategory);
            pCategories.AddRange(cannotDeleteParents);

            numberOfCategory -= pCategories.Count;

            if (numberOfCategory > 0)
            {
                var additions = categories.Where(c => !pCategories.Contains(c) && c.ParentProductCategoryId == null).Take(numberOfCategory);
                pCategories.AddRange(additions);
            }

            var cloneResult = new List<ProductCategory>(pCategories);
            foreach (var pCategory in cloneResult)
            {
                random = new Random((int)DateTime.Now.Ticks);
                var numberOfChildren = random.Next(minNumberOfSubCategory, maxNumberOfSubCategory);
                var children = categories.Where(c => c.ParentProductCategoryId == pCategory.ProductCategoryId).ToList();
                numberOfChildren = numberOfChildren > children.Count ? children.Count : numberOfChildren;
                var mustAdd = children.Where(c => cannotDeleteParents.Contains(c)).Take(numberOfChildren).ToList();
                
                numberOfChildren -= mustAdd.Count;
                if (numberOfChildren > 0)
                {
                    children = children.Where(c => !mustAdd.Contains(c)).Take(numberOfChildren).ToList();
                    mustAdd.AddRange(children);
                }

                pCategories.AddRange(mustAdd);
            }

            var disableList = categories.Where(c => !pCategories.Contains(c)).ToList();
            foreach (var c in disableList)
                DisableProductCategory(c.ProductCategoryId);

            pCategoryRepo.Dispose();

            return pCategories;
        }
            
    }
}
